`timescale 1ns / 1ps
/******************************************************************************
*                                                                             *
* UTICA softcore v0.1                                                         *
*                                                                             *
* Copyright (c) 2012 Andrew D. Zonenberg                                      *
* All rights reserved.                                                        *
*                                                                             *
* Redistribution and use in source and binary forms, with or without modifi-  *
* cation, are permitted provided that the following conditions are met:       *
*                                                                             *
*    * Redistributions of source code must retain the above copyright notice  *
*      this list of conditions and the following disclaimer.                  *
*                                                                             *
*    * Redistributions in binary form must reproduce the above copyright      *
*      notice, this list of conditions and the following disclaimer in the    *
*      documentation and/or other materials provided with the distribution.   *
*                                                                             *
*    * Neither the name of the author nor the names of any contributors may be*
*      used to endorse or promote products derived from this software without *
*      specific prior written permission.                                     *
*                                                                             *
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR IMPLIED *
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF        *
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN     *
* NO EVENT SHALL THE AUTHORS BE HELD LIABLE FOR ANY DIRECT, INDIRECT,         *
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT    *
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,   *
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY       *
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT         *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF    *
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.           *
*                                                                             *
******************************************************************************/

/**
	@file UticaCPUWritebackForwarding.v
	@author Andrew D. Zonenberg
	@brief Forwarding / muxes for register file writeback
 */
module UticaCPUWritebackForwarding(
	writeback_lw, writeback_lb, writeback_lbu, writeback_lh, writeback_lhu, writeback_lowaddr,
	dbus_din, dbus_dinok,
	writeback_rdval,
	writeback_rdval_forwarded,
	writeback_memread, writeback_cachemiss, writeback_mfhi, writeback_mflo,
	postwb2_mult, postwb2_multu,
	mdu_hi_forwarded, mdu_lo_forwarded
    );
	 
	input wire writeback_lw;
	input wire writeback_lb;
	input wire writeback_lbu;
	input wire writeback_lh;
	input wire writeback_lhu;
	input wire[1:0] writeback_lowaddr;
	 
	input wire[31:0] dbus_din;
	input wire[31:0] writeback_rdval;
	
	input wire writeback_memread;
	input wire dbus_dinok;
	
	output wire writeback_cachemiss;
	assign writeback_cachemiss = writeback_memread && !dbus_dinok;	//if we read but it didnt come back, cache miss
	
	input wire postwb2_mult;
	input wire postwb2_multu;
	input wire writeback_mfhi;
	input wire writeback_mflo;
	input wire[31:0] mdu_hi_forwarded;
	input wire[31:0] mdu_lo_forwarded;

	//Forwarding from memory to register file
	output reg[31:0] writeback_rdval_forwarded = 0;
	always @(writeback_lw, writeback_lb, writeback_lbu, writeback_lh, writeback_lhu, writeback_lowaddr, writeback_mfhi, writeback_mflo,
				dbus_din, mdu_hi_forwarded, mdu_lo_forwarded, postwb2_mult, postwb2_multu,
				writeback_rdval) begin

		if(writeback_lw)
			writeback_rdval_forwarded <= dbus_din;
		else if(writeback_lb) begin
			//Pull the proper byte out of the word and sign extend it
			case(writeback_lowaddr)
				2'd0: writeback_rdval_forwarded <= { {24{dbus_din[7]}}, dbus_din[7:0] };
				2'd1: writeback_rdval_forwarded <= { {24{dbus_din[15]}}, dbus_din[15:8] };
				2'd2: writeback_rdval_forwarded <= { {24{dbus_din[23]}}, dbus_din[23:16] };
				2'd3: writeback_rdval_forwarded <= { {24{dbus_din[31]}}, dbus_din[31:24] };
			endcase
		end
		else if(writeback_lbu) begin
			//Pull the proper byte out of the word and zero extend it
			case(writeback_lowaddr)
				2'd0: writeback_rdval_forwarded <= { 24'b0, dbus_din[7:0] };
				2'd1: writeback_rdval_forwarded <= { 24'b0, dbus_din[15:8] };
				2'd2: writeback_rdval_forwarded <= { 24'b0, dbus_din[23:16] };
				2'd3: writeback_rdval_forwarded <= { 24'b0, dbus_din[31:24] };
			endcase
		end
		else if(writeback_lh) begin
			//Pull the proper half out of the word and sign extend it
			if(!writeback_lowaddr[1])
				writeback_rdval_forwarded <= { {16{dbus_din[15]}}, dbus_din[15:0] };
			else
				writeback_rdval_forwarded <= { {16{dbus_din[31]}}, dbus_din[31:16] };
		end
		else if(writeback_lhu) begin
			//Pull the proper half out of the word and zero extend it
			if(!writeback_lowaddr[1])
				writeback_rdval_forwarded <= { 16'b0, dbus_din[15:0] };
			else
				writeback_rdval_forwarded <= { 16'b0, dbus_din[31:16] };
		end
		else if(writeback_mfhi && (postwb2_mult || postwb2_multu) ) begin
			writeback_rdval_forwarded <= mdu_hi_forwarded;
		end
		else if(writeback_mflo && (postwb2_mult || postwb2_multu) ) begin
			writeback_rdval_forwarded <= mdu_lo_forwarded;
		end
		else
			writeback_rdval_forwarded <= writeback_rdval;
		
	end

endmodule
